#include <iostream>
#include <string>
#include <chrono>
#include <thread>
#include <mosquittopp.h>
using namespace std;

class mqtt_client : public mosqpp::mosquittopp
{
public:
    mqtt_client(const string id, const string &host, int port)
        : mosquittopp(id.c_str()), host_(host), port_(port)
    {
    }

    bool connect()
    {
        int rc = mosquittopp::connect(host_.c_str(), port_, 60);
        return rc == MOSQ_ERR_SUCCESS;
    }

    void subscribe(const string &topic)
    {
        int rc = mosquittopp::subscribe(nullptr, topic.c_str());
        if (rc == MOSQ_ERR_SUCCESS)
        {
            cout << "subscribe topic: " << topic << endl;
        }
        else
        {
            cerr << "subscribe failed topic: " << topic << endl;
        }
    }

    void publish(const string &topic, const string &msg)
    {
        int rc = mosquittopp::publish(nullptr, topic.c_str(), msg.size(), msg.c_str());
        if (rc == MOSQ_ERR_SUCCESS)
        {
            cout << "publish topic >> " << topic << ": " << msg << endl;
        }
        else
        {
            cerr << "publish failed topic: " << topic << endl;
        }
    }

protected:
    virtual void on_connect(int rc) override
    {
        cout << "on_connect: " << rc << endl;
    }

    virtual void on_subscribe(int mid, int qos_count, const int *granted_qos) override
    {
        cout << "on_subscribe: id=" << mid << " qos_count=" << qos_count << endl;
    }

    virtual void on_message(const struct mosquitto_message *msg) override
    {
        cout << "recv topic:: " << msg->topic << " : " << string(static_cast<const char *>(msg->payload), msg->payloadlen) << endl;
    }

private:
    string host_;
    int port_;
};

void get_input_publish(mqtt_client &mqtt)
{
    string msg;
    while (true)
    {
        cout << "input msg: ";
        cin >> msg;
        mqtt.publish("test/topic", msg);
        if (msg == "exit" || msg == "quit")
        {
            break;
        }
    }
}

int main(int argc, char *argv[])
{
    mosqpp::lib_init();
    mqtt_client mqtt("test", "127.0.0.1", 1883);
    if (mqtt.connect())
    {
        mqtt.subscribe("test/topic");
        mqtt.publish("test/topic", "hello world");
    }
    thread task(get_input_publish, ref(mqtt));
    task.detach();

    while (true)
    {
        mqtt.loop(1000);
    }
    mosqpp::lib_cleanup();

    return 0;
}